热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

表里|层面_ShardingJDBC第一篇:分库分表

篇首语:本文由编程笔记#小编为大家整理,主要介绍了ShardingJDBC第一篇:分库分表相关的知识,希望对你有一定的参考价值。文章目录

篇首语:本文由编程笔记#小编为大家整理,主要介绍了ShardingJDBC第一篇:分库分表相关的知识,希望对你有一定的参考价值。



文章目录


  • 一、前言
  • 二、关系型数据库层面的高并发优化
    • 2.1 MYSQL海量数据带来的性能问题
    • 2.2 分片策略
    • 2.3 分布式ID
      • 2.3.1 定义全局表
      • 2.3.2 UUID
      • 2.3.3 雪花算法


  • 三、Sharding-JDBC分库分表
    • 3.1 Sharding-JDBC内置算法
    • 3.2 取模算法
    • 3.3 基于分片容量的范围分片算法
    • 3.4 基于分片边界的范围分片算法
    • 3.5 自动时间段分片算法
    • 3.6 同时分库分表

  • 四、尾声


一、前言

本文从高并发出发,主要介绍了ShardingJDBC分库分表。

本文代码如下:sharding-jdbc-split分库分表demo工程代码


二、关系型数据库层面的高并发优化

2.1 mysql海量数据带来的性能问题

根据阿里开发手册, 单表行数超过500W或者单表数据容量超过2G,需要考虑水平分表;根据mysql官网,一个表中列数超过1017列,开发者记住1000列就好,需要考虑垂直分表。即行数和数据容量不够,水平分表,列数不够,垂直分表,如下:



eg: 水平有水平分表和水平分库,垂直有垂直分表(商品表、商品明细表)和 垂直分库(订单库、商品库、用户库)


水平分表涉及的问题有三个:

第一个问题是确定分片策略:水平分表存在一个无法避免的问题是,需要决定根据哪个字段将一个表拆分为多个表,这就是分片字段,决定使用哪个分片字段、决定如何对目标表分片的就是分片策略,常见的分片策略方案包括:哈希取模分片算法、一致性哈希分片算法(哈希环偏斜)、范围分片算法。

第二个问题是确定分布式ID:需要额外自定义一个字段来存储全局唯一的主键,即分布式ID,因为mysql的物理主键只能保证在一个表内唯一,水平分表将一个表变为多个表,而这个数据库的水平分表对前端来说是透明的,前端需要做 select * from tablename where 主键列= ‘xxx’ 这种类型操作,不能再用id列,常见的方式是水平分表的每个表增加一个额外的列,用uuid或者雪花算法保证唯一。都能保证唯一性,但是用雪花算法比uuid要好,因为uuid没有任何意义,雪花算法可以存储时间戳。

第三个问题是引入依赖:需要让后端Java代码中像操作一个表一样,去操作水平分表之后的多个表,要么在服务端代码中引入Sharding-JDBC依赖,要么是在linux上独立安装ShardingSphere这个中间件,两者的原理是一样的,只是一个在服务端代码层面实现,一个在数据库层面实现。


2.2 分片策略

哈希取模分片:通过表中的某一个字段进行hash算法得到一个哈希值,然后通过取模运算确定数据应该放在哪个分片中,这种方式非常适合随机读写的场景中,它能够很好的将一个大表的数据随机分散到多个小表,前提是哈希算法要设计的好,就是要均衡,如下:

哈希取模运算最大的优点是简单,“先哈希再取模”就好了,最大的缺点是无法适应业务需求的变化,假设根据当前数据表的量以及增长情况,我们把一个大表拆分成了4个小表,看起来满足目前的需求,但是经过一段时间的运行后,发现四个表不够,需要再增加4个表来存储,就是一共需要8个表,这种情况下,就需要对原来的数据进行整体迁移,这个过程非常麻烦。即一旦目标表或者数据库发生数量上的变化,就会导致所有数据都需要进行迁移,为了减少这种大规模的数据影响,所以引入了一致性hash算法,这也是现实开发中更常见的一种做法。

一致性哈希算法:将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数的值空间为 0 ~ 2^ 32 -1 ,就是我们通过 0 ~ 2^ 32 -1 的数字组成一个虚拟的圆环,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^ 32 -1,也就是说0点左侧的第一个点代表2^ 32
-1。我们把这个由2的32次方个点组成的圆环称为hash环。

假设现在水平分表出四个表,table_1、table_2、table_3、table_4,在一致性hash算法中,取模运算不是直接对这四个表来完成,而是对2^ 32来实现。hash(table编号)%2^ 32 通过上述公式算出的结果一定是一个0到2^ 32-1之间的一个整数,然后在这个数对应的位置标注目标表,四个表通过hash取模之后分别落在hash环的某个位置上,如下:


当添加一条数据时,同样通过hash和hash环取模运算得到一个目标值,然后根据目标值所在的hash环的位置顺时针查找最近的一个目标表,把数据存储到这个目标表中即可,所以,哈希环的作用也是帮助我们确定某条记录最终要插入到哪个表中,需要到哪个表中找到某条记录,如下:


一致性哈希运算不是直接面向目标表,而是面向hash环,这样的好处就是当需要删除某张表或者增加表的时候,对于整个数据变化的影响是局部的,而不是全局。即插入和删除一个表,只会影响后面那个表。增加一个表,只需要将一些数据从新表的下一个表的移动到新表就可以了;删除一个表,只需要将删除表里面的数据移动到下一个表里就可以了。

理论上,各个表表是能够均衡的分布在整个hash环中,然后每个新插入的记录就是均衡的分布到水平分表的各个表里面,但实际情况如下:

也就是产生了hash环偏斜的现象,这种现象导致的问题就是大量的数据都会保存到同一个表中,导致数据分配极度不均匀,如上图,很多数据会被存入到表table_01中。

解决的办法是把这四个节点分别复制一份出来分散到这个hash环中,这个复制出来的节点叫虚拟节点,根据实际需要可以虚拟出多个节点出来,注意这里是按实际需要来,比如可以给table_02、table_03、table_04各虚拟出一个,也可以给table_02虚拟出三个。

范围分片:基于数据表的业务特性,按照某种范围拆分,这个范围的有很多含义,比如:

① 时间范围,比如我们按照数据创建时间,按照每一个月保存一个表。基于时间划分还可以用来做冷热数据分离,越早的数据访问频次越少。
② 区域范围,区域一般指的是地理位置,比如一个表里面存储了来自全国各地的数据,如果数据量较大的情况下,可以按照地域来划分多个表。
③ 数据范围,比如根据某个字段的数据区间来进行划分。


2.3 分布式ID

分布式ID的特性
① 唯一性:确保生成的ID是全局唯一的。
② 有序递增性:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的。
③ 高可用性:确保任何时候都能正确的生成ID。
④ 带时间:ID里面包含时间,一眼扫过去就知道哪天的数据

分布式id方案大概有:
① 数据库自增ID(定义全局表)
② UUID
③ Twitter-Snowflake算法


2.3.1 定义全局表

在数据库中专门创建一张序列表,利用数据库表中的自增ID来为其他业务的数据生成一个全局ID,那么每次要用ID的时候,直接从这个表中获取即可。

CREATE TABLE `uid_table` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `business_id` int(11) NOT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE (business_type) )

在应用程序中,每次调用下面这段代码,就可以持续获得一个递增的ID。

begin
replace into uid_table (business_id) values(2);
select last_insert_id();
commit;

其中,replace into是每次删除原来相同的数据,同时加1条,就能保证我们每次得到的就是一个自增的ID。

优点:
非常简单,利用现有数据库系统的功能实现,成本小,有DBA专业维护。
ID号单调自增,可以实现一些对ID有特殊要求的业务。
缺点:
强依赖DB,当DB异常时整个系统不可用,属于致命问题。配置主从复制可以尽可能的增加可用
性,但是数据一致性在特殊情况下难以保证。主从切换时的不一致可能会导致重复发号。
ID发号性能瓶颈限制在单台MySQL的读写性能。


2.3.2 UUID

UUID的格式是: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 8-4-4-4-12共36个字符,它是一个128bit的
二进制转化为16进制的32个字符,然后用4个 - 连接起来的字符串。

UUID的五种生成方式
① 基于时间的UUID(date-time & MAC address): 主要依赖当前的时间戳及机器mac地址,因此
可以保证全球唯一性。(使用了Mac地址,因此会暴露Mac地址和生成时间。)
② 分布式安全的UUID(date-time & group/user id)将版本1的时间戳前四位换为POSIX的UID或
GID。
③ 基于名字空间的UUID-MD5版(MD5 hash & namespace),基于指定的名字空间/名字生成MD5
散列值得到,标准不推荐。
④ 基于随机数的UUID(pseudo-random number):基于随机数或伪随机数生成。
⑤ 基于名字空间的UUID-SHA1版(SHA-1 hash & namespace):将版本3的散列算法改为SHA1。

在Java中,提供了基于MD5算法的UUID、以及基于随机数的UUID。

优点:本地生成,没有网络消耗,生成简单,没有高可用风险。

缺点:
① 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。
② 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅
丽莎病毒的制作者位置。
③ 无序查询效率低:由于生成的UUID是无序不可读的字符串,所以其查询效率低。
④ UUID不适合用来做数据库的唯一ID,如果用UUID做主键,无序的不递增,大家都知道,主键是有
索引的,然后mysql的索引是通过b+树来实现的,每一次新的UUID数据的插入,为了查询的优化,都会对索引底层的b+树进行修改,因为UUID数据是无序的,所以每一次UUID数据的插入都会对主键的b+树进行很大的修改,严重影响性能


2.3.3 雪花算法

SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型
的数字作为全局唯一 id。雪花算法的组成,一共64bit,这64个bit位由四个部分组成。

第一部分,1bit位,用来表示符号位,而ID一般是正数,所以这个符号位一般情况下是0。

第二部分,占41 个 bit:表示的是时间戳,是系统时间的毫秒数,但是这个时间戳不是当前系统的
时间,而是当前 系统时间-开始时间 ,即表示这个ID生成方案的使用的时间,时间戳是为了保证有序性,可读性,即开发者一看就能猜到ID是什么时候生成的。41位可以2^ 41 - 1表示个数字,可以表示的数值范围是:0 至 2^ 41-1,也就是说41位可以表示2^ 41-1个毫秒的值,转化成单位年则是(2^ 41-1)/1000 * 60 * 60 * 24*365=69年,也就是能容纳69年的时间。

第三部分,用来记录工作机器id,id包含10bit,意味着这个服务最多可以部署在 2^10 台机器上,
也就是 1024 台机器。其中这10bit又可以分成2个5bit,前5bit表示机房id、5bit表示机器id,意味着最多支持2^5个机房(32),每个机房可以支持32台机器。

第四部分,由12bit组成,表示一个递增序列,用来记录同毫秒内产生的不同id。如果是同一毫秒同一台机器来请求,需要使用序列号来保证唯一性,即保证同一毫秒内同一机器生成的ID是唯一的,这个其实就是为了满足我们ID的这个高并发,就是保证我同一毫秒进来的并发场景的唯一性。12位(bit)可以表示的最大正整数是2^12-1=4095,即可以用0、1、2、3、…4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。12位2进制,如果全部都是1的情况下,那么最终的值就是4095,也就是12bit能够存储的最大的数字是4095。


三、Sharding-JDBC分库分表

3.1 Sharding-JDBC内置算法

访问官网 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding/ ,主要包括四种

分片算法:用来分库分表,常见的就是取模
分布式序列算法:用来生成全局id,包括uuid和雪花算法
负载均衡算法:用来做读写分离,多个库中选择一个写库进行操作
加密算法:用来加密解密



这里将分库分表,所有主要看分片算法就好,分布式序列算法就直接用雪花算法。


3.2 取模算法

取模算法需要我们自己实现一个算法,直接取模操作,如下:

运行生成四个表,如下:

其实还有一种哈希取模分片算法,即定位到 HashModShardingAlgorithm 类的 doSharding 方法,先哈希,再取模,如下:


3.3 基于分片容量的范围分片算法

基于分片容量的范围分片算法就是VOLUME_RANGE,如下:



插入600条数据,且按照user_id分表,每个表就是200条,所以运行之后生成三个表,每个表中200条数据


3.4 基于分片边界的范围分片算法


运行生成四个表,按照userid字段值分表,如下:


3.5 自动时间段分片算法


运行生成13个表,如下:


3.6 同时分库分表

上面都只有将一个表的数据存放到同一个库的多个表中,其实我们可以将一个表存放到多个库多个表中,如下:





未水平分表,数据仅在一个表中,查询语句走 “索引字段”;
水平分表后,之后从查询语句要走 “分片字段+索引字段” 。



四、尾声

本文从高并发出发,主要介绍了ShardingJDBC分库分表,本文代码如下:sharding-jdbc-split分库分表demo工程代码

天天打码,天天进步!!


推荐阅读
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • 深入了解 Windows 窗体中的 SplitContainer 控件
    SplitContainer 控件是 Windows 窗体中的一种复合控件,由两个可调整大小的面板和一个可移动的拆分条组成。本文将详细介绍其功能、属性以及如何通过编程方式创建复杂的用户界面。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • HBase运维工具全解析
    本文深入探讨了HBase常用的运维工具,详细介绍了每种工具的功能、使用场景及操作示例。对于HBase的开发人员和运维工程师来说,这些工具是日常管理和故障排查的重要手段。 ... [详细]
  • 2018年3月31日,CSDN、火星财经联合中关村区块链产业联盟等机构举办的2018区块链技术及应用峰会(BTA)核心分会场圆满举行。多位业内顶尖专家深入探讨了区块链的核心技术原理及其在实际业务中的应用。 ... [详细]
  • 开发笔记:9.八大排序
    开发笔记:9.八大排序 ... [详细]
  • 对象自省自省在计算机编程领域里,是指在运行时判断一个对象的类型和能力。dir能够返回一个列表,列举了一个对象所拥有的属性和方法。my_list[ ... [详细]
  • openGauss每日一练:第6天 - 模式的创建、修改与删除
    本篇笔记记录了openGauss数据库中关于模式(Schema)的创建、修改和删除操作。通过这些操作,用户可以更好地管理和控制数据库对象。实验环境为openGauss 2.0.0,并使用由墨天轮提供的线上环境。 ... [详细]
  • 本文探讨了MariaDB在当前数据库市场中的地位和挑战,分析其可能面临的困境,并提出了对未来发展的几点看法。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 本文探讨了在Oracle数据库中,动态SQL语句的执行及其对事务管理的影响,特别是关于回滚操作的有效性。重点讨论了一个具体场景:将预警短信从当前表迁移到历史表时遇到的字段长度不匹配问题及相应的异常处理。 ... [详细]
author-avatar
元元木樨_669
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有